package com.bobo.mm.socket.provider;

import android.util.Log;

import com.bobo.mm.ClientConfig;
import com.bobo.mm.socket.InnerSocketListener;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
import java.util.Objects;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;

/**
 * 基于okhttp的websocket
 * Created by cocolove2 on 2020/8/10.
 */
public class OkWebSocketClient extends BaseSocketClient {
    private static final String TAG = "OkWebSocketClient";
    private WebSocket mWebSocket;
    private final MyWebSocketListener mMyWebSocketListener;

    public OkWebSocketClient(@NotNull ClientConfig clientConfig, @NotNull InnerSocketListener listener) {
        super(clientConfig, listener);
        mMyWebSocketListener = new MyWebSocketListener(clientConfig.getClientId());
    }

    private void createWebSocket() {
        Request request = new Request.Builder().url(getClientConfig().getWebsocketUrl()).build();
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)
                .build();
        mWebSocket = okHttpClient.newWebSocket(request, mMyWebSocketListener);
    }

    @Override
    public void startConnect() {
        buildConnect();
    }

    @Override
    public void stopConnect() {
        super.stopConnect();
        if (getClientConnState() == DISCONNECTED) {
            return;
        }
        if (mWebSocket != null) {
            mWebSocket.cancel();
            boolean isClosed = mWebSocket.close(CODE_NORMAL_CLOSE, TIP_NORMAL_CLOSE);
            //非正常关闭连接
            if (!isClosed) {
                mMyWebSocketListener.onClosed(mWebSocket, CODE_ABNORMAL_CLOSE, TIP_ABNORMAL_CLOSE);
            }
        }
        setClientConnState(DISCONNECTED);
    }

    @Override
    void reconnect(String clientId, int reconCount) {
        setClientConnState(RECONNECT);
        getSocketListener().onReconnecting(getClientConfig().getClientId(), reconCount);
        buildConnect();
    }


    @Override
    public boolean sendMessage(String msg) {
        return mWebSocket.send(msg);
    }

    @Override
    public boolean sendMessage(byte[] data) {
        return mWebSocket.send(ByteString.of(data));
    }


    private synchronized void buildConnect() {
        switch (getClientConnState()) {
            case CONNECTED:
            case CONNECTING:
                break;
            default:
                setClientConnState(CONNECTING);
                createWebSocket();
        }
    }


    private class MyWebSocketListener extends WebSocketListener {
        private InnerSocketListener mSocketListener;
        private String clientId;

        MyWebSocketListener(String clientId) {
            mSocketListener = Objects.requireNonNull(getSocketListener());
            this.clientId = Objects.requireNonNull(clientId);
        }

        @Override
        public void onOpen(@NotNull WebSocket webSocket, @NotNull final Response response) {
            setClientConnState(CONNECTED);
            //停止重连服务
            stopReconHandler();
            try {
                if (response.body() != null) {
                    mSocketListener.onOpen(clientId, Objects.requireNonNull(response.body()).bytes());
                } else {
                    mSocketListener.onOpen(clientId, null);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onMessage(@NotNull WebSocket webSocket, @NotNull String text) {
            Log.d(TAG, "onMessage==>" + text);
            mSocketListener.onMessage(clientId, text);
        }

        @Override
        public void onMessage(@NotNull WebSocket webSocket, @NotNull ByteString bytes) {
            mSocketListener.onMessage(clientId, bytes.toByteArray());
        }

        @Override
        public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) {
            Log.w(TAG, "onClosing==>" + code + "#" + reason);
            mSocketListener.onClosing(clientId, code, reason);
        }

        @Override
        public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) {
            Log.w(TAG, "onClosed==>" + code + "#" + reason);
            mSocketListener.onClosed(clientId, code, reason);
        }

        @Override
        public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) {
            setClientConnState(DISCONNECTED);
            if ("Socket closed".equals(t.getMessage())) {
                Log.i(TAG, "正常关闭抛出的异常，不处理");
                return;
            }
            Log.e(TAG, "onFailure==>" + t.getMessage() + "#");
            t.printStackTrace();
            mSocketListener.onFailure(clientId, t, response);
            //开启重连服务
            if (!isReconning())
                startReConHandler();
        }
    }
}
